// 2010年版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package json

import (
	"bytes"
	"errors"
	"io"
)

// 解码器从输入流读取并解码JSON值。
type Decoder struct {
	r       io.Reader
	buf     []byte
	d       decodeState
	scanp   int   // buf中未读数据的开始
	scanned int64 // 已扫描的数据量
	scan    scanner
	err     error

	tokenState int
	tokenStack []int
}

// NewDecoder返回从r读取的新解码器。
// None
// 解码器引入了自己的缓冲，并且可以
// 从r读取超出请求的JSON值的数据。
func NewDecoder(r io.Reader) *Decoder {
	return &Decoder{r: r}
}

// UseNumber使解码器将数字解组到接口{}中作为
// 数字而不是浮点数64。
func (dec *Decoder) UseNumber() { dec.d.useNumber = true }

// 禁用Wunknownfields会导致解码器在接收到目标时返回错误
// 是一个结构，输入包含与任何
// 目标中非忽略的导出字段。
func (dec *Decoder) DisallowUnknownFields() { dec.d.disallowUnknownFields = true }

// Decode从其源代码中读取下一个JSON编码的值
// 输入并存储在v指向的值中。
// None
// 有关详细信息，请参阅解组的文档
// 将JSON转换为Go值。
func (dec *Decoder) Decode(v interface{}) error {
	if dec.err != nil {
		return dec.err
	}

	if err := dec.tokenPrepareForDecode(); err != nil {
		return err
	}

	if !dec.tokenValueAllowed() {
		return &SyntaxError{msg: "not at beginning of value", Offset: dec.InputOffset()}
	}

	// 将整个值读入缓冲区。
	n, err := dec.readValue()
	if err != nil {
		return err
	}
	dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
	dec.scanp += n

	// 不将错误从解组保存到dec.err：
	// 由于我们读取了完整的JSON，所以连接仍然可用
	// 在错误发生之前从中删除对象。
	err = dec.d.unmarshal(v)

	// 修复令牌流状态
	dec.tokenValueEnd()

	return err
}

// Buffered返回解码器中剩余数据的读取器
// 缓冲器读取器在下一次调用解码之前有效。
func (dec *Decoder) Buffered() io.Reader {
	return bytes.NewReader(dec.buf[dec.scanp:])
}

// readValue将JSON值读入dec.buf。
// 它返回编码的长度。
func (dec *Decoder) readValue() (int, error) {
	dec.scan.reset()

	scanp := dec.scanp
	var err error
Input:
	// 帮助编译器看到scanp从来都不是负数，因此它可以删除
	// 下面是一些边界检查。
	for scanp >= 0 {

		// 在缓冲区中查找新值。
		for ; scanp < len(dec.buf); scanp++ {
			c := dec.buf[scanp]
			dec.scan.bytes++
			switch dec.scan.step(&dec.scan, c) {
			case scanEnd:
				// 扫描结束延迟一个字节，因此我们减少
				// 扫描仪字节计数为1，以确保
				// 此值在下一次调用Decode时是正确的。
				dec.scan.bytes--
				break Input
			case scanEndObject, scanEndArray:
				// 扫描结束延迟一个字节。
				// 我们可能会阻止从src获取该字节，
				// 因此，我们应该发明一个空格字节。
				if stateEndValue(&dec.scan, ' ') == scanEnd {
					scanp++
					break Input
				}
			case scanError:
				dec.err = dec.scan.err
				return 0, dec.scan.err
			}
		}

		// 上次读取有错误吗？
		// 延迟到现在，以允许缓冲区扫描。
		if err != nil {
			if err == io.EOF {
				if dec.scan.step(&dec.scan, ' ') == scanEnd {
					break Input
				}
				if nonSpace(dec.buf) {
					err = io.ErrUnexpectedEOF
				}
			}
			dec.err = err
			return 0, err
		}

		n := scanp - dec.scanp
		err = dec.refill()
		scanp = dec.scanp + n
	}
	return scanp - dec.scanp, nil
}

func (dec *Decoder) refill() error {
	// 腾出空间阅读缓冲区中的更多内容。
	// 第一个向下滑动的数据已被消耗。
	if dec.scanp > 0 {
		dec.scanned += int64(dec.scanp)
		n := copy(dec.buf, dec.buf[dec.scanp:])
		dec.buf = dec.buf[:n]
		dec.scanp = 0
	}

	// 如果缓冲区不够大，则增加缓冲区。
	const minRead = 512
	if cap(dec.buf)-len(dec.buf) < minRead {
		newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
		copy(newBuf, dec.buf)
		dec.buf = newBuf
	}

	// 阅读下一次迭代的延迟错误（扫描后）。
	n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
	dec.buf = dec.buf[0 : len(dec.buf)+n]

	return err
}

func nonSpace(b []byte) bool {
	for _, c := range b {
		if !isSpace(c) {
			return true
		}
	}
	return false
}

// 编码器将JSON值写入输出流。
type Encoder struct {
	w          io.Writer
	err        error
	escapeHTML bool

	indentBuf    *bytes.Buffer
	indentPrefix string
	indentValue  string
}

// NewEncoder返回写入w的新编码器。
func NewEncoder(w io.Writer) *Encoder {
	return &Encoder{w: w, escapeHTML: true}
}

// Encode将v的JSON编码写入流，
// 后跟换行符。
// None
// 有关封送处理的详细信息，请参阅封送处理文档
// 将Go值转换为JSON。
func (enc *Encoder) Encode(v interface{}) error {
	if enc.err != nil {
		return enc.err
	}
	e := newEncodeState()
	err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
	if err != nil {
		return err
	}

	// 用换行符终止每个值。
	// 这使输出看起来更好一些
	// 调试时，和某种空间
	// 如果编码值是数字，则为必需，
	// 这样读者就知道没有更多了
	// 数字来了。
	e.WriteByte('\n')

	b := e.Bytes()
	if enc.indentPrefix != "" || enc.indentValue != "" {
		if enc.indentBuf == nil {
			enc.indentBuf = new(bytes.Buffer)
		}
		enc.indentBuf.Reset()
		err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
		if err != nil {
			return err
		}
		b = enc.indentBuf.Bytes()
	}
	if _, err = enc.w.Write(b); err != nil {
		enc.err = err
	}
	encodeStatePool.Put(e)
	return err
}

// SetIndent指示编码器格式化每个后续编码
// 值，如同由包级函数Indent（dst、src、prefix、Indent）缩进一样。
// 调用SetIndent（“，”）将禁用缩进。
func (enc *Encoder) SetIndent(prefix, indent string) {
	enc.indentPrefix = prefix
	enc.indentValue = indent
}

// SetEscapeHTML指定是否存在问题的HTML字符
// 应在带JSON引号的字符串中转义。
// 默认行为是将&、<和>转义到\u0026、\u003c和\u003e
// 避免在HTML中嵌入JSON时可能出现的某些安全问题。
// None
// 在非HTML设置中，转义会干扰可读性
// 对于输出，SetEscapeHTML（false）禁用此行为。
func (enc *Encoder) SetEscapeHTML(on bool) {
	enc.escapeHTML = on
}

// RawMessage是一个原始编码的JSON值。
// 它实现封送器和解封送器以及can
// 用于延迟JSON解码或预计算JSON编码。
type RawMessage []byte

// MarshalJSON返回m作为m的JSON编码。
func (m RawMessage) MarshalJSON() ([]byte, error) {
	if m == nil {
		return []byte("null"), nil
	}
	return m, nil
}

// 解组JSON将*m设置为数据的副本。
func (m *RawMessage) UnmarshalJSON(data []byte) error {
	if m == nil {
		return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
	}
	*m = append((*m)[0:0], data...)
	return nil
}

var _ Marshaler = (*RawMessage)(nil)
var _ Unmarshaler = (*RawMessage)(nil)

// 令牌持有以下类型之一的值：
// None
// Delim，用于四个JSON分隔符[]{}
// bool，用于JSON布尔值
// float64，用于JSON数字
// 编号，用于JSON编号
// 字符串，用于JSON字符串文本
// nil，对于JSON null
// None
type Token interface{}

const (
	tokenTopValue = iota
	tokenArrayStart
	tokenArrayValue
	tokenArrayComma
	tokenObjectStart
	tokenObjectKey
	tokenObjectColon
	tokenObjectValue
	tokenObjectComma
)

// 将标记状态从分隔符状态提升到值状态
func (dec *Decoder) tokenPrepareForDecode() error {
	// 注意：切换前不要调用peek，以避免
	// 将peek放入标准解码路径。
	// peek仅在使用令牌API时调用。
	switch dec.tokenState {
	case tokenArrayComma:
		c, err := dec.peek()
		if err != nil {
			return err
		}
		if c != ',' {
			return &SyntaxError{"expected comma after array element", dec.InputOffset()}
		}
		dec.scanp++
		dec.tokenState = tokenArrayValue
	case tokenObjectColon:
		c, err := dec.peek()
		if err != nil {
			return err
		}
		if c != ':' {
			return &SyntaxError{"expected colon after object key", dec.InputOffset()}
		}
		dec.scanp++
		dec.tokenState = tokenObjectValue
	}
	return nil
}

func (dec *Decoder) tokenValueAllowed() bool {
	switch dec.tokenState {
	case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue:
		return true
	}
	return false
}

func (dec *Decoder) tokenValueEnd() {
	switch dec.tokenState {
	case tokenArrayStart, tokenArrayValue:
		dec.tokenState = tokenArrayComma
	case tokenObjectValue:
		dec.tokenState = tokenObjectComma
	}
}

// Delim是一个JSON数组或对象分隔符，[]{或}之一。
type Delim rune

func (d Delim) String() string {
	return string(d)
}

// 令牌返回输入流中的下一个JSON令牌。
// 在输入流的末尾，Token返回nil，io.EOF。
// None
// 令牌保证它返回的分隔符[]{}是
// 正确嵌套和匹配：如果令牌遇到意外
// 输入中的分隔符，它将返回一个错误。
// None
// 输入流由基本JSON值bool、string、，
// 数字和null以及Delim类型的分隔符[]{}
// 标记数组和对象的开始和结束。
// 省略逗号和冒号。
func (dec *Decoder) Token() (Token, error) {
	for {
		c, err := dec.peek()
		if err != nil {
			return nil, err
		}
		switch c {
		case '[':
			if !dec.tokenValueAllowed() {
				return dec.tokenError(c)
			}
			dec.scanp++
			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
			dec.tokenState = tokenArrayStart
			return Delim('['), nil

		case ']':
			if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma {
				return dec.tokenError(c)
			}
			dec.scanp++
			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
			dec.tokenValueEnd()
			return Delim(']'), nil

		case '{':
			if !dec.tokenValueAllowed() {
				return dec.tokenError(c)
			}
			dec.scanp++
			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
			dec.tokenState = tokenObjectStart
			return Delim('{'), nil

		case '}':
			if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma {
				return dec.tokenError(c)
			}
			dec.scanp++
			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
			dec.tokenValueEnd()
			return Delim('}'), nil

		case ':':
			if dec.tokenState != tokenObjectColon {
				return dec.tokenError(c)
			}
			dec.scanp++
			dec.tokenState = tokenObjectValue
			continue

		case ',':
			if dec.tokenState == tokenArrayComma {
				dec.scanp++
				dec.tokenState = tokenArrayValue
				continue
			}
			if dec.tokenState == tokenObjectComma {
				dec.scanp++
				dec.tokenState = tokenObjectKey
				continue
			}
			return dec.tokenError(c)

		case '"':
			if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey {
				var x string
				old := dec.tokenState
				dec.tokenState = tokenTopValue
				err := dec.Decode(&x)
				dec.tokenState = old
				if err != nil {
					return nil, err
				}
				dec.tokenState = tokenObjectColon
				return x, nil
			}
			fallthrough

		default:
			if !dec.tokenValueAllowed() {
				return dec.tokenError(c)
			}
			var x interface{}
			if err := dec.Decode(&x); err != nil {
				return nil, err
			}
			return x, nil
		}
	}
}

func (dec *Decoder) tokenError(c byte) (Token, error) {
	var context string
	switch dec.tokenState {
	case tokenTopValue:
		context = " looking for beginning of value"
	case tokenArrayStart, tokenArrayValue, tokenObjectValue:
		context = " looking for beginning of value"
	case tokenArrayComma:
		context = " after array element"
	case tokenObjectKey:
		context = " looking for beginning of object key string"
	case tokenObjectColon:
		context = " after object key"
	case tokenObjectComma:
		context = " after object key:value pair"
	}
	return nil, &SyntaxError{"invalid character " + quoteChar(c) + context, dec.InputOffset()}
}

// 更多报告中是否有其他元素
// 正在分析的当前数组或对象。
func (dec *Decoder) More() bool {
	c, err := dec.peek()
	return err == nil && c != ']' && c != '}'
}

func (dec *Decoder) peek() (byte, error) {
	var err error
	for {
		for i := dec.scanp; i < len(dec.buf); i++ {
			c := dec.buf[i]
			if isSpace(c) {
				continue
			}
			dec.scanp = i
			return c, nil
		}
		// 缓冲区已扫描，现在报告任何错误
		if err != nil {
			return 0, err
		}
		err = dec.refill()
	}
}

// InputOffset返回当前解码器位置的输入流字节偏移量。
// 偏移量给出最近返回的令牌的结束位置
// 和下一个标记的开始。
func (dec *Decoder) InputOffset() int64 {
	return dec.scanned + int64(dec.scanp)
}
